package config

import (
	"errors"
	"fmt"
	"os"
	"path/filepath"
	"sync"

	"github.com/spf13/viper"
)

// Config is a singleton that holds the YAML configuration.
type Config struct {
	sync.RWMutex
	// 全局配置读取和保存
	myViper *viper.Viper
	// 配文件文件路径
	configPath string
}

var (
	instance *Config
	once     sync.Once
)

// GetInstance returns the global Config singleton.
func GetInstance() *Config {
	once.Do(func() {
		instance = &Config{
			myViper: viper.New(),
		}
		// 默认配置路径
		instance.configPath = "./application.yaml"
	})
	return instance
}

// InitConfig initializes the configuration by loading the YAML file.
func (c *Config) InitConfig() error {
	c.Lock()
	defer c.Unlock()

	// 确保配置路径存在
	if c.configPath == "" {
		return errors.New("config path is not set")
	}
	// 解析路径，文件名和尾缀
	dir, fileName, ext := c.parsePath(c.configPath)

	c.myViper.AddConfigPath(dir)
	c.myViper.SetConfigName(fileName)
	c.myViper.SetConfigType(ext)
	// 解析 YAML 数据
	err := c.myViper.ReadInConfig()
	if err != nil {
		return fmt.Errorf("failed to parse YAML: %v", err)
	}

	return nil
}

// ParsePath 解析文件路径并返回路径、文件名和尾缀
func (c *Config) parsePath(filePath string) (string, string, string) {
	// 分割路径和文件名
	dir, file := filepath.Split(filePath)
	// 获取尾缀
	ext := filepath.Ext(file)
	// 文件名部分去掉尾缀
	fileName := file[:len(file)-len(ext)]
	// 处理尾缀，去掉前面的点
	if len(ext) > 0 {
		ext = ext[1:]
	} else {
		ext = ""
	}
	
	return dir, fileName, ext
}

// SetConfigPath sets the configuration file path.
func (c *Config) SetConfigPath(path string) error {
	c.Lock()
	defer c.Unlock()

	if path == "" {
		return errors.New("config path cannot be empty")
	}

	// 检查文件路径是否有效
	if _, err := os.Stat(path); os.IsNotExist(err) {
		return fmt.Errorf("config file not found at path: %s", path)
	}

	// 设置路径
	c.configPath = filepath.Clean(path)
	return nil
}

// GetValue retrieves a configuration value by key.
func (c *Config) GetString(key string) string {
	c.RLock()
	defer c.RUnlock()

	return c.myViper.GetString(key)
}

func (c *Config) GetBool(key string) bool {
	c.RLock()
	defer c.RUnlock()

	return c.myViper.GetBool(key)
}

func (c *Config) GetInt32(key string) int32 {
	c.RLock()
	defer c.RUnlock()

	return c.myViper.GetInt32(key)
}

func (c *Config) GetInt64(key string) int64 {
	c.RLock()
	defer c.RUnlock()

	return c.myViper.GetInt64(key)
}
